package com.yingxue.lesson.service.impl;

import com.github.pagehelper.PageHelper;
import com.yingxue.lesson.config.TokenSettings;
import com.yingxue.lesson.constant.Constant;
import com.yingxue.lesson.dao.SysDeptDao;
import com.yingxue.lesson.dao.SysUserDao;
import com.yingxue.lesson.entity.SysDept;
import com.yingxue.lesson.entity.SysUser;
import com.yingxue.lesson.exception.BaseResponseCode;
import com.yingxue.lesson.exception.BusinessException;
import com.yingxue.lesson.service.*;
import com.yingxue.lesson.utils.JwtTokenUtil;
import com.yingxue.lesson.utils.PageUtils;
import com.yingxue.lesson.utils.PasswordUtils;
import com.yingxue.lesson.utils.RedisService;
import com.yingxue.lesson.vo.req.*;
import com.yingxue.lesson.vo.resp.LoginRespVO;
import com.yingxue.lesson.vo.resp.PageVO;
import com.yingxue.lesson.vo.resp.UserOwnRoleRespVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * (SysUser)表服务实现类
 *
 * @author makejava
 * @since 2022-04-04 23:12:05
 */
@Service("sysUserService")
@Slf4j
public class SysUserServiceImpl implements SysUserService {

    @Resource
    private SysUserDao sysUserDao;

    @Autowired
    private SysUserRoleService sysUserRoleService;

    @Autowired
    private SysRoleService sysRoleService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private TokenSettings tokenSettings;

    @Autowired
    private SysPermissionService sysPermissionService;

    @Autowired
    private SysDeptDao sysDeptDao;

    @Override
    public PageVO<SysUser> pageInfo(UserPageReqVO vo) {
        PageHelper.startPage(vo.getPageNum(),vo.getPageSize());
        List<SysUser> list=sysUserDao.selectAll(vo);
        for (SysUser sysUser:list){
            SysDept sysDept = sysDeptDao.selectByPrimaryKey(sysUser.getDeptId());
            if(sysDept!=null){
                sysUser.setDeptName(sysDept.getName());
            }
        }
        return PageUtils.getPageVO(list);
    }

    @Override
    public LoginRespVO login(LoginReqVO vo) {
        SysUser sysUser=sysUserDao.getUserInfoByName(vo.getUsername());
        if (null==sysUser){
            throw new BusinessException(BaseResponseCode.ACCOUNT_ERROR);
        }
        if (sysUser.getStatus()==2){
            throw new BusinessException(BaseResponseCode.ACCOUNT_LOCK);
        }
        if(!PasswordUtils.matches(sysUser.getSalt(),vo.getPassword(),sysUser.getPassword())){
            throw new BusinessException(BaseResponseCode.ACCOUNT_PASSWORD_ERROR);
        }

        LoginRespVO respVO=new LoginRespVO();
        BeanUtils.copyProperties(sysUser,respVO);

        Map<String,Object> claims=new HashMap<>();
        claims.put(Constant.PERMISSIONS_INFOS_KEY,getPermissionsByUserId(sysUser.getId()));
        claims.put(Constant.ROLES_INFOS_KEY,getRolesByUserId(sysUser.getId()));
        claims.put(Constant.JWT_USER_NAME,sysUser.getUsername());
        String access_token= JwtTokenUtil.getAccessToken(sysUser.getId(),claims);

        String refresh_token;
        Map<String,Object> refreshTokenClaims=new HashMap<>();
        refreshTokenClaims.put(Constant.JWT_USER_NAME,sysUser.getUsername());
        if(vo.getType().equals("1")){
            refresh_token=JwtTokenUtil.getRefreshToken(sysUser.getId(),refreshTokenClaims);
        }else {
            refresh_token=JwtTokenUtil.getRefreshAppToken(sysUser.getId(),refreshTokenClaims);
        }
        respVO.setAccessToken(access_token);
        respVO.setRefreshToken(refresh_token);
        return respVO;
    }

    /**
     * 获取用户的角色，这里先用伪代码代替
     */
    private List<String> getRolesByUserId(String userId){
        List<String> list=new ArrayList<>();
        if("9a26f5f1-cbd2-473d-82db-1d6dcf4598f8".equals(userId)){
            list.add("admin");
        }else{
            list.add("test");
        }
        return  list;
    }

    /**
     * 获取用户的权限，这里先用伪代码代替
     */
    private List<String>getPermissionsByUserId(String userId){
        List<String> list=new ArrayList<>();
        if("9a26f5f1-cbd2-473d-82db-1d6dcf4598f8".equals(userId)){
            list.add("sys:user:add");
            list.add("sys:user:list");
            list.add("sys:user:update");
            list.add("sys:user:detail");
        }else{
            list.add("sys:user:list");
        }
        return  list;
    }


    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public SysUser queryById(String id) {
        return this.sysUserDao.queryById(id);
    }

    /**
     * 分页查询
     *
     * @param sysUser 筛选条件
     * @param pageRequest      分页对象
     * @return 查询结果
     */
    @Override
    public Page<SysUser> queryByPage(SysUser sysUser, PageRequest pageRequest) {
        long total = this.sysUserDao.count(sysUser);
        return new PageImpl<>(this.sysUserDao.queryAllByLimit(sysUser, pageRequest), pageRequest, total);
    }

    @Override
    public SysUser insert(SysUser sysUser) {
        return null;
    }

    @Override
    public SysUser update(SysUser sysUser) {
        return null;
    }

    @Override
    public boolean deleteById(String id) {
        return false;
    }

    /**
     * 新增用户
     * @param userAddReqVO
     */
    @Override
    public void addUser(UserAddReqVO userAddReqVO) {
        SysUser sysUser = new SysUser();
        BeanUtils.copyProperties(userAddReqVO,sysUser);
        sysUser.setId(UUID.randomUUID().toString());
        // 对密码加密后保存
        String salt=PasswordUtils.getSalt();
        String ecdPwd=PasswordUtils.encode(userAddReqVO.getPassword(),salt);
        sysUser.setSalt(salt);
        sysUser.setPassword(ecdPwd);
        sysUser.setCreateTime(new Date());
        sysUserDao.insertSelective(sysUser);
    }

    @Override
    public UserOwnRoleRespVO getUserOwnRole(String userId) {
        UserOwnRoleRespVO respVO=new UserOwnRoleRespVO();
        respVO.setOwnRoles(sysUserRoleService.getRoleIdsByUserId(userId));
        respVO.setAllRole(sysRoleService.selectAll());
        return respVO;
    }

    @Override
    public void setUserOwnRole(UserOwnRoleReqVO vo) {
        sysUserRoleService.addUserRoleInfo(vo);
        /**
         * 标记用户 要主动去刷新
         */
        redisService.set(Constant.JWT_REFRESH_KEY+vo.getUserId(),vo.getUserId(),tokenSettings.getAccessTokenExpireTime().toMillis(), TimeUnit.MILLISECONDS);
        /**
         * 清除用户授权数据缓存
         */
        redisService.delete(Constant.IDENTIFY_CACHE_KEY+vo.getUserId());
    }

    @Override
    public String refreshToken(String refreshToken) {
        //它是否过期
        //它是否被加如了黑名
        if(!JwtTokenUtil.validateToken(refreshToken)
                || redisService.hasKey(Constant.JWT_REFRESH_TOKEN_BLACKLIST+refreshToken)){
            throw new BusinessException(BaseResponseCode.TOKEN_ERROR);
        }

        String userId=JwtTokenUtil.getUserId(refreshToken);
        String username=JwtTokenUtil.getUserName(refreshToken);
        log.info("userId={}",userId);
        Map<String,Object> claims=new HashMap<>();

        // 重新获取用户的角色
        claims.put(Constant.ROLES_INFOS_KEY,getRolesByUserId(userId));
        // 重新获取用户的权限信息
        claims.put(Constant.PERMISSIONS_INFOS_KEY,getPermissionsByUserId(userId));
        // 重新获取用户的姓名
        claims.put(Constant.JWT_USER_NAME,username);
        // 给客户端签发一个新的access_token
        String newAccessToken= JwtTokenUtil.getAccessToken(userId,claims);
        return newAccessToken;
    }

    @Override
    public void updateUserInfo(UserUpdateReqVO vo, String operationId) {
        SysUser sysUser=new SysUser();
        BeanUtils.copyProperties(vo,sysUser);
        sysUser.setUpdateTime(new Date());
        sysUser.setUpdateId(operationId);

        // 设置密码
        if(StringUtils.isEmpty(vo.getPassword())){
            sysUser.setPassword(null);
        }else {
            String salt=PasswordUtils.getSalt();
            String endPwd=PasswordUtils.encode(vo.getPassword(),salt);
            sysUser.setSalt(salt);
            sysUser.setPassword(endPwd);
        }

        int i = sysUserDao.updateByPrimaryKeySelective(sysUser);
        if(i!=1){
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }


        if(vo.getStatus()==2){
            // 用户被锁定
            redisService.set(Constant.ACCOUNT_LOCK_KEY+vo.getId(),vo.getId());
        }else {
            // 解除锁定
            redisService.delete(Constant.ACCOUNT_LOCK_KEY+vo.getId());
        }
    }

    @Override
    public void deletedUsers(List<String> list, String operationId) {
        SysUser sysUser=new SysUser();
        sysUser.setUpdateId(operationId);
        sysUser.setUpdateTime(new Date());
        int i = sysUserDao.deletedUsers(sysUser, list);
        if(i==0){
            throw new BusinessException(BaseResponseCode.OPERATION_ERROR);
        }

        for (String userId: list) {
            redisService.set(Constant.DELETED_USER_KEY+userId,userId,tokenSettings.getRefreshTokenExpireAppTime().toMillis(),TimeUnit.MILLISECONDS);
            /**
             * 清楚用户授权数据缓存
             */
            redisService.delete(Constant.IDENTIFY_CACHE_KEY+userId);
        }
    }

    private List<String> getPermissionByUserId(String userId){
        return sysPermissionService.getPermissionByUserId(userId);
    }

    private List<String> getRoleByUserId(String userId){
        return sysRoleService.getNamesByUserId(userId);
    }
}
